---
title: Middleware
description: Apprendre à utiliser un middleware dans Astro.
i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro';
import { Steps } from '@astrojs/starlight/components';
import Since from '~/components/Since.astro';

Un **middleware** vous permet d'intercepter les demandes et les réponses et d'injecter des comportements de manière dynamique chaque fois qu'une page ou un point de terminaison est sur le point d'être rendu. Ce rendu a lieu au moment de la compilation pour toutes les pages pré-rendues, mais il a lieu lorsque la route est demandée pour les pages rendues à la demande, rendant disponibles [des fonctionnalités SSR supplémentaires telles que les cookies et les en-têtes](/fr/guides/on-demand-rendering/#fonctionnalités-de-rendu-à-la-demande).

Un middleware vous permet également de définir et de partager des informations spécifiques aux requêtes entre les points de terminaison et les pages en modifiant un objet `locals` disponible dans tous les composants Astro et les points de terminaison de l'API. Cet objet est disponible même lorsque ce middleware s'exécute au moment de la compilation.

## Utilisation basique

<Steps>
1. Créez `src/middleware.js|ts` (Alternativement, vous pouvez créer `src/middleware/index.js|ts`.)

2. Dans ce fichier, exportez une fonction [`onRequest()`](/fr/reference/modules/astro-middleware/#onrequest) à laquelle il est possible de transmettre un objet [`context`](#objet-context) et une fonction `next()`. Il ne doit pas s'agir d'une exportation par défaut.

    ```js title="src/middleware.js"
    export function onRequest (context, next) {
         // intercepter les données d'une requête
         // optionnellement, modifie la propriété dans `locals`
         context.locals.title = "Nouveau titre";

         // renvoie une réponse (Response) ou le résultat de l'appel à `next()`
         return next();
    };
    ```

3. Dans n'importe quel fichier `.astro`, accédez aux données de la réponse en utilisant `Astro.locals`.

    ```astro title="src/components/Component.astro"
    ---
    const data = Astro.locals;
    ---
    <h1>{data.title}</h1>
    <p>Cette {data.property} provient du middleware.</p>
    ```
</Steps>

### Objet `context`

L'objet [`context`](/fr/reference/api-reference/) inclut des informations à mettre à disposition d'autres middlewares, routes d'API et routes `.astro` pendant le processus de rendu.

C'est un argument optionnel passé à `onRequest()` qui peut contenir l'objet `locals` ainsi que toutes les propriétés additionnelles à partager pendant le rendu. Par exemple, l'objet `context` peut inclure les cookies utilisés pour l'authentification.

### Stocker des données dans `context.locals`

`context.locals` est un objet pouvant être manipulé dans le middleware. 

Cet objet `locals` est transmis à travers le processus de traitement des requêtes et est disponible en tant que propriété pour [`APIContext`](/fr/reference/api-reference/#locals) et [`AstroGlobal`](/fr/reference/api-reference/#locals). Cela permet de partager des données entre les middlewares, les routes API et les pages `.astro`. Ceci est utile pour stocker des données spécifiques à une requête, telles que les données de l'utilisateur, à travers l'étape de rendu.

:::tip[Propriétés des intégrations]
Les [intégrations](/fr/guides/integrations-guide/) peuvent définir des propriétés et fournir des fonctionnalités à travers l'objet `locals`. Si vous utilisez une intégration, vérifiez sa documentation pour vous assurer que vous ne surchargez aucune de ses propriétés et que vous ne faites pas de travail inutile.
:::

Vous pouvez stocker n'importe quel type de données dans `locals` : des chaînes de caractères, des nombres, et même des types de données complexes tels que des fonctions et des cartes.

```js title="src/middleware.js"
export function onRequest (context, next) {
    // intercepter les données de réponse d'une requête
    // optionnellement, modifie la propriété dans `locals`
    context.locals.user.name = "John Wick";
    context.locals.welcomeTitle = () => {
        return "Welcome back " + locals.user.name;
    };

    // renvoie une réponse (`Response`) ou le résultat de l'appel à `next()`
    return next();
};
```

Vous pouvez ensuite utiliser ces informations dans n'importe quel fichier `.astro` avec `Astro.locals`.

```astro title="src/pages/orders.astro"
---
const title = Astro.locals.welcomeTitle();
const orders = Array.from(Astro.locals.orders.entries());
const data = Astro.locals;
---
<h1>{title}</h1>
<p>Cette {data.property} provient du middleware.</p>
<ul>
    {orders.map(order => {
        return <li>{/* faire quelque chose avec order */}</li>;
    })}
</ul>
```

`locals` est un objet qui vit et meurt au sein d'une seule route Astro ; lorsque la page de votre route est rendue, `locals` n'existera plus et un nouvel objet sera créé. Les informations qui doivent persister à travers plusieurs requêtes de pages doivent être stockées ailleurs.

:::note
La valeur de `locals` ne peut pas être modifiée au moment de l'exécution. Cela risquerait d'effacer toutes les informations stockées par l'utilisateur.  Astro effectue des vérifications et génère une erreur si la valeur de `locals` est remplacée.
:::

### Exemple : supprimer des informations sensibles

L'exemple ci-dessous utilise un middleware pour remplacer « PRIVATE INFO » par le mot « REDACTED » afin de vous permettre d'afficher le code HTML modifié sur votre page :

```js title="src/middleware.js"
export const onRequest = async (context, next) => {
    const response = await next();
    const html = await response.text();
    const redactedHtml = html.replaceAll("PRIVATE INFO", "REDACTED");
    
    return new Response(redactedHtml, {
        status: 200,
        headers: response.headers
    });
};
```

### Types du middleware

Vous pouvez importer et utiliser la fonction utilitaire `defineMiddleware()` pour bénéficier de la sûreté du typage :

```ts
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";

// `context` et `next` sont automatiquement typés
export const onRequest = defineMiddleware((context, next) => {

});
```

A la place, si vous utilisez JsDoc pour profiter de la sûreté du typage, vous pouvez utiliser `MiddlewareHandler` :

```js
// src/middleware.js
/**
 * @type {import("astro").MiddlewareHandler}
 */
// `context` et `next` sont automatiquement typés
export const onRequest = (context, next) => {

};
```

Pour ajouter des types aux informations contenues dans `Astro.locals`, qui vous donne l'autocomplétion dans les fichiers `.astro` et le code du middleware, [étendez les types globaux](/fr/guides/typescript/#extension-des-types-globaux) en déclarant un espace de noms global dans le fichier `env.d.ts` :

```ts title="src/env.d.ts"
type User = {
  id: number;
  name: string;
};

declare namespace App {
  interface Locals {
    user: User;
    welcomeTitle: () => string;
    orders: Map<string, object>;
    session: import("./lib/server/session").Session | null;
  }
}
```

Ensuite, dans le fichier du middleware, vous pouvez tirer parti de l'autocomplétion et de la sûreté du typage.

## Enchaînement de middlewares

Plusieurs middlewares peuvent être reliés dans un ordre précis à l'aide de [`sequence()`](/fr/reference/modules/astro-middleware/#sequence) :

```js title="src/middleware.js"
import { sequence } from "astro/middleware";

async function validation(_, next) {
    console.log("demande de validation");
    const response = await next();
    console.log("réponse de validation");
    return response;
}

async function auth(_, next) {
    console.log("demande d'authentification");
    const response = await next();
    console.log("réponse d'authentification");
    return response;
}

async function greeting(_, next) {
    console.log("demande de salutation");
    const response = await next();
    console.log("réponse de salutation");
    return response;
}

export const onRequest = sequence(validation, auth, greeting);
```

L'ordre de la console sera alors le suivant :

```sh
demande de validation
demande d'authentification
demande de salutation
réponse de salutation
réponse d'authentification
réponse de validation
```

## Réécriture

<p><Since v="4.13.0" /></p>

L'`APIContext` expose une méthode appelée `rewrite()` qui fonctionne de la même manière que [Astro.rewrite](/fr/guides/routing/#réécritures).

Utilisez `context.rewrite()` dans un middleware pour afficher le contenu d'une autre page sans [rediriger](/fr/guides/routing/#redirections-dynamiques) votre visiteur vers une nouvelle page. Cela déclenchera une nouvelle phase d'affichage, entraînant la ré-exécution de tout middleware.

```js title="src/middleware.js"
import { isLoggedIn } from "~/auth.js"
export function onRequest (context, next) {
  if (!isLoggedIn(context)) {
    // Si l'utilisateur n'est pas connecté, mettre à jour la requête pour afficher la route `/login` et
    // ajouter un en-tête pour indiquer où l'utilisateur doit être envoyé après une connexion réussie.
    // Ré-exécuter le middleware.
    return context.rewrite(new Request("/login", {
      headers: {
        "x-redirect-to": context.url.pathname
      }
    }));
  }

  return next();
};
```

Vous pouvez également passer à la fonction `next()` un paramètre optionnel de chemin URL pour réécrire la requête (`Request`) actuelle sans réenclencher une nouvelle phase de rendu. L'emplacement du chemin de réécriture peut être fourni sous la forme d'une chaîne de caractères, d'une URL ou d'une requête (`Request`) :

```js title="src/middleware.js"
import { isLoggedIn } from "~/auth.js"
export function onRequest (context, next) {
  if (!isLoggedIn(context) {
    // Si l'utilisateur n'est pas connecté, mettre à jour la requête pour afficher la route `/login` et
    // ajouter un en-tête pour indiquer où l'utilisateur doit être envoyé après une connexion réussie.
    // Renvoyer un nouveau contexte (`context`) à tous les middlewares suivants.
    return next(new Request("/login", {
      headers: {
        "x-redirect-to": context.url.pathname
      }
    }));
  }

  return next();
};
```

La fonction `next()` accepte la même charge utile que [la fonction `Astro.rewrite()`](/fr/reference/api-reference/#rewrite). L'emplacement du chemin de réécriture peut être fourni sous la forme d'une chaîne de caractères, d'une URL ou d'une requête (`Request`).

Quand vous avez plusieurs fonctions middleware enchaînées via [sequence()](#enchaînement-de-middlewares), soumettre un chemin à `next()` réécrira la requête (`Request`) en place et le middleware ne s'exécutera pas à nouveau. Le middleware suivant dans la chaîne recevra la nouvelle requête (`Request`) avec son contexte (`context`) mis à jour :

L'appel de `next()` avec cette signature créera un nouvel objet `Request` en utilisant l'ancien contexte de requête (`ctx.request`). Cela signifie que toute tentative de consommation de `Request.body`, avant ou après cette réécriture, générera une erreur d'exécution. Cette erreur est souvent générée avec [les actions Astro qui utilisent des formulaires HTML](/fr/guides/actions/#appeler-des-actions-depuis-une-action-de-formulaire-html). Dans ces cas, nous vous recommandons de gérer les réécritures de vos modèles Astro à l'aide de `Astro.rewrite()` au lieu d'utiliser un middleware.

```js title="src/middleware.js"
// L'URL actuelle est https://example.com/blog

// Première fonction du middleware
async function first(context, next) {
  console.log(context.url.pathname) // ceci enregistrera "/blog"
  // Réécriture vers une nouvelle route, la page d'accueil 
  // Retourne le `context` mis à jour qui est passé à la fonction suivante
  return next("/")
}

// L'URL actuelle est toujours https://example.com/blog

// Deuxième fonction du middleware
async function second(context, next) {
  // Reçoit la mise à jour du `context`
  console.log(context.url.pathname) // Cela affichera dans la console « / »    
  return next()
}

export const onRequest = sequence(first, second);
```

## Pages d'erreur

Un middleware tentera de s'exécuter pour toutes les pages rendues à la demande, même lorsqu'une route correspondante ne peut être trouvée. Cela inclut la page 404 par défaut (vide) d'Astro et toutes les pages 404 personnalisées. Cependant, c'est à l'[adaptateur](/fr/guides/on-demand-rendering/) de décider si ce code s'exécute. Certains adaptateurs peuvent servir une page d'erreur spécifique à la plate-forme à la place.

Un middleware tentera également de s'exécuter avant de servir une page d'erreur 500, y compris une page 500 personnalisée, sauf si l'erreur du serveur s'est produite lors de l'exécution du middleware lui-même. Si votre middleware ne s'exécute pas correctement, vous n'aurez pas accès à `Astro.locals` pour générer votre page 500.
